﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;

using System.IO;

namespace SFR
{
    public class MongoDbHelper
    {
        string _dbName;
        MongoClient cli;
        MongoServer ms;
        MongoDatabase md;
        MongoGridFS gfs;

        public MongoDbHelper()
        {
            //try
            //{
            //    _dbName = "docs";

            //    var url = new MongoUrl("mongodb://localhost:27017");

            //    cli = new MongoClient(url);

            //    ms = cli.GetServer();

            //    md = ms.GetDatabase(_dbName);

            //    gfs = new MongoGridFS(md);
            //}
            //catch (Exception ex)
            //{
            //    System.Windows.Forms.MessageBox.Show("Error: " + ex.Message);
            //}

            Initilaize("mongodb://localhost:27017");

        }

        public void Initilaize(string connString)
        {
            try
            {
                _dbName = "docs";

                var url = new MongoUrl(connString);

                cli = new MongoClient(url);

                ms = cli.GetServer();

                md = ms.GetDatabase(_dbName);

                gfs = new MongoGridFS(md);
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Error: " + ex.Message);
            }
        }

        public Doc[] GetAll()
        {
            MongoCollection<BsonDocument> _documents = md.GetCollection<BsonDocument>(_dbName);

            var q = from d in _documents.FindAll()
                    select new Doc(d);

            return q.ToArray();
        }

        public Doc[] Search(Dictionary<string,bool> SelectedTags, string text)
        {
            MongoCollection<BsonDocument> _documents = md.GetCollection<BsonDocument>(_dbName);

            //if (SelectedTags.Keys.Count == 0)
            //{
            //    return GetAll();
            //}
            //else
            {
                IMongoQuery query = null;

                if (SelectedTags.Keys.Count > 0)
                {
                    //use selected tags to build query
                    var k = from t in SelectedTags.Keys
                            select Query.EQ(t, SelectedTags[t]);
                    query = Query.And(k.ToArray());
                }

                if (text != "")
                {
                    text = @".*" + text + ".*";

                    if (query == null)
                        query = Query.Matches("DocName", text);
                    else Query.Or(query, Query.Matches("DocName", text));

                    query = Query.Or(query, Query.Matches("SubjectName", text));
                    query = Query.Or(query, Query.Matches("Comment", text));
                }

                var q = from d in _documents.Find(query)
                        select new Doc(d);

                return q.ToArray();
            }
        }

        public void ImportFile(Doc doc,string filePath)
        {
            if (!md.CollectionExists(_dbName))
            {
                md.CreateCollection(_dbName);
            }

            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            MongoGridFSFileInfo gfsi = gfs.Upload(filePath);

            doc.GridFsId = gfsi.Id.AsObjectId;

            //save primary fields for document
            WriteConcernResult wc = _documents.Insert(doc);
 
            //save tags for the same document

            //we rertrieve the same document but as bson to avoid serialization to bson
            MongoCollection<BsonDocument> _documentsAsBson = md.GetCollection<BsonDocument>(_dbName);
            BsonDocument bsondoc = _documentsAsBson.FindOne(Query.EQ("_id", doc.Id));

            //BsonWriter w = new BsonBinaryWriter();
            //BsonSerializer.Serialize<Doc>(doc);
            foreach (string s in doc.Tags.Keys)
            {
                bsondoc.Add(s, doc.Tags[s]);
            }

            //update document with the tags
            _documentsAsBson.Save(bsondoc);
        }

        public void ExportFile(Doc doc,string fullpath)
        {
            ObjectId _documentid = new ObjectId(doc.GridFsId.ToString());

            MongoGridFSFileInfo _fileInfo = md.GridFS.FindOne(Query.EQ("_id", _documentid));

            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            FileStream fs = new FileStream(fullpath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            gfs.Download(fs, _fileInfo);
            fs.Close();
        }

        public void Delete(Doc item)
        {
            ObjectId _documentid = new ObjectId(item.GridFsId.ToString());

            MongoGridFSFileInfo _fileInfo = md.GridFS.FindOne(Query.EQ("_id", _documentid));

            gfs.DeleteById(_documentid);

            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            _documents.Remove(Query.EQ("_id",  item.Id));
        }

        public void DropDb()
        {
            md.Drop();
            gfs.Files.Drop();
            gfs.Chunks.Drop();
        }

        public void ClearAllEntries()
        {
            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            foreach (Doc item in _documents.FindAll())
            {

                ObjectId _documentid = new ObjectId(item.GridFsId.ToString());

                MongoGridFSFileInfo _fileInfo = md.GridFS.FindOne(Query.EQ("_id", _documentid));

                gfs.DeleteById(_documentid);
            }

            _documents.RemoveAll();

            gfs.Database.RunCommand("repairDatabase");
        }
    }
}
